
背景
Discuz! X5.0 论坛原生自带 RESTful API,支持通过 OAuth2.0 风格签名认证进行发帖、回帖、版块管理等操作。目标是把 Typecho 博客文章自动同步发布到 Discuz! 论坛,实现内容的多端分发。本文记录 RESTful API 的两种认证模式、实测结论,以及新版标准模式下遇到的认证与脚本分发问题及根因。
过程
问题描述
论坛部署于 www.example.com(Discuz! X5.0,内测中),需要拿到一套稳定的 API 调用方式,能完成「创建帖子 → 上传附件 → 创建版块」等操作。Discuz! X5.0 的 RESTful API 入口在 /api/restful/index.php,支持两套认证机制。
两种认证模式
模式一:旧模式(appid + secret 放在查询参数)
直接在 URL query 里携带 appid 与 secret,例如:
/api/restful/index.php?appid=<appid>&secret=<secret>&url=/forum/thread/list/实测该模式下大量接口均可用(已验证全通过):
| 模块 | 接口 |
|---|---|
| forum | thread/list、thread/create、thread/update、thread/delete、post/list、post/create、post/update、post/delete、forum/list、forum/create、forum/update、forum/delete、attachment/list、attachment/create |
| member | register、login、logout、profile、update、delete |
| 其他 | group/list、site/setting、site/check、portal/list、portal/article/list、follow/list、follow/create、follow/delete |
细节一:旧模式 URL 末尾必须带斜杠(如/forum/thread/list/),否则会被重定向到/admin.php。
模式二:新版标准 OAuth2.0(header 签名)
通过请求头携带认证信息,签名算法为:
sign = base64( sha256_hex( nonce + t + secret ) )其中 nonce 为随机字符串,t 为当前 Unix 时间戳。请求头为:Appid、Nonce、T、Sign。先取 token:
GET /api/restful/index.php?/token
Headers: Appid, Nonce, T, Sign成功返回 {"ret":0,"token":"..."}。取到 token 后,后续业务请求额外携带 Token 头。
细节二:PHP 的 hash('sha256',...) 默认返回十六进制字符串,因此签名时需先对 hex digest 做 base64,而不是直接对原始串做 base64。卡点与排查
新版认证里,token 获取可以成功,但业务接口调用出现三类报错:
-118 scriptCheck: script format is error-114 initParam: api is invalid-101 checkSign: param is missing(改用旧模式 query 参数时,说明该认证只认 header、不认 query)
逐一排查后发现,接口定义数据(存在 Redis,key 形如 rApi_/<baseuri>_<ver>)中,script 字段是带斜杠的旧格式:
/thread/newthread → script: forum/thread/newthread
/user/user → script: user/login而 Discuz! X5.0 的 scriptCheck() 要求 script 必须匹配 ^\w+$,也就是纯单段:字符串里不能有斜杠、只能由单词字符组成。分发逻辑为:
$_GET['app'] = $script;
require index.php; // → source/app/<单段>/<单段>.php因此,凡是带斜杠的 script 定义,最终都会在 scriptCheck() 处返回 -118 script format is error。这套 Redis 里的接口定义格式属于旧版/错误格式,与 X5.0 的期望不兼容——这是新版发帖打不开的根本原因。
同时确认了另外两条链路的状态:
- 旧模式(query 参数):发帖可全通,可作为稳定兜底方案。
- 新版标准模式:卡在 script 格式,需要把接口定义改造成单段格式。
关键机制备忘
- Redis 键:
rApi_<接口>存接口定义,rApp_<appid>存应用信息(secret、apis、freq 等)。RESTFUL_REDIS_PREFIX为空字符串,所以键不带前缀。 - 脚本执行:根入口按
$_GET['app']分发到source/app/<单段>/<单段>.php(带\w+校验)。 - 存在单段应用
source/app/forum/forum.php(含 post 模块,具备发帖能力)。 - 权限校验:
apiPermCheck()读取 token 数据中的_conf.apis,来自pre_restful_permission表的 uri/vN。 - 应用 appid 格式为「1 + 7 位数字」,secret 由后台生成;Redis
rApp_<appid>读取不到会返回-110 appid is invalid。 - 注意:若应用建在 UCenter 库上,而 UCenter 的 nginx 未把
/api/restful/转发到 PHP 侧,则该入口会 404。
解决方案
新版发帖要打通,推荐按下面顺序尝试:
- 修正接口定义为单段 script 格式:在后台重建 RESTful 接口缓存(
build_cache_restful())或手动修正pre_restful_api.data里的 script 字段为单段(如把forum/thread/newthread改成可被分发的单段值)。 - 用单段 script + module 参数发帖:直接以
script='forum'单段 + module 参数尝试调用,验证能否发帖。 - 从后台导入官方接口定义:Discuz! 官方在线源
api.witframe.com/discuzrestful可能存在正确格式的默认接口 XML(如discuz_restful.xml),可从后台「RESTful 接口 → 导入」引入。
若以上短期都不顺,可直接回退到已全通的旧模式(query 参数)作为稳定方案,先跑通博客→论坛同步,新版标准模式再逐步优化。
总结
正确做法
- 调用新版 Discuz! X5.0 RESTful API 前,先确认接口定义(Redis
rApi_*)里的 script 是单段格式(符合^\w+$),否则必然返回-118。 - 旧模式 API 记得给 URL 补末尾斜杠,避免被重定向。
- 签名计算要基于 sha256 的 hex digest 再做 base64。
- 处理这类「官方自带 API」前,先读
source/class/class_restful.php理清认证、缓存、脚本分发三段逻辑,能大幅缩短定位时间。
参考
- Typecho 博客:
https://blog.example.com - Discuz! X5.0 官方源码:
https://github.com/DiscuzTeam/DiscuzX
觉得内容不错?我要